﻿/*! \file strutil_inl.h
    \brief 字符串相关工具函数实现
*/

#pragma once
#include <string>
#include <algorithm>
#include <functional>
#include "base/platform.h"

namespace acutil{
  namespace string{
    namespace internal{
      void Trim(std::string& s);
      void Trim(std::wstring& s);
    }

    template <typename CharT, typename StringContainer>
    std::basic_string<CharT> Join(const StringContainer& string_list, const std::basic_string<CharT>& seperator){
      std::basic_string<CharT> s_r;
      std::basic_string<CharT>::size_type size_r = seperator.size() * string_list.size();
      StringContainer::const_iterator it = string_list.begin();
      for (; it != string_list.end(); ++it){
        size_r += it->size();
      }
      s_r.reserve(size_r);
      for (it = string_list.begin(); it != string_list.end(); ++it){
        if (it != string_list.begin())
          s_r.insert(s_r.end(), seperator.begin(), seperator.end());
        s_r.insert(s_r.end(), it->begin(), it->end());
      }
      return AC_STDMOVE(s_r);
    }

    template <typename CharT>
    std::basic_string<CharT> Lower(const std::basic_string<CharT>& s){
      std::basic_string<CharT> s_r;
      s_r.resize(s.size());
      std::transform(s.begin(), s.end(), s_r.begin(), tolower);
      return AC_STDMOVE(s_r);
    }

    template <typename CharT>
    std::basic_string<CharT> Upper(const std::basic_string<CharT>& s){
      std::basic_string<CharT> s_r;
      s_r.resize(s.size());
      std::transform(s.begin(), s.end(), s_r.begin(), toupper);
      return AC_STDMOVE(s_r);
    }

    template <typename CharT>
    void ToLower(std::basic_string<CharT>& s){
      std::transform(s.begin(), s.end(), s.begin(), tolower);
    }

    template <typename CharT>
    void ToUpper(std::basic_string<CharT>& s){
      std::transform(s.begin(), s.end(), s.begin(), toupper);
    }

    template <typename CharT>
    void TrimStart(std::basic_string<CharT>& s, const std::basic_string<CharT>& trim_chars){
      s.erase(0, s.find_first_not_of(trim_chars.c_str(), trim_chars.size()));
    }

    template <typename CharT>
    void TrimEnd(std::basic_string<CharT>& s, const std::basic_string<CharT>& trim_chars){
      s.erase(s.find_last_not_of(trim_chars.c_str(), trim_chars.size()) + 1);
    }

    template <typename CharT>
    void Trim(std::basic_string<CharT>& s, const std::basic_string<CharT>& trim_chars){
      TrimEnd(s, trim_chars);
      TrimStart(s, trim_chars);
    }

    template <typename CharT, typename Predicate>
    void TrimStart_If(std::basic_string<CharT>& s, const Predicate& pred){
      std::basic_string<CharT>::iterator it = s.begin();
      for (; it < s.end(); ++it)
        if (!pred(*it))
          break;
      s.erase(s.begin(), it);
    }

    template <typename CharT, typename Predicate>
    void TrimEnd_If(std::basic_string<CharT>& s, const Predicate& pred){
      std::basic_string<CharT>::reverse_iterator it = s.rbegin();
      for (; it < s.rend(); ++it)
        if (!pred(*it))
          break;
      s.erase(it.base(), s.end());
    }

    template <typename CharT, typename Predicate>
    void Trim_If(std::basic_string<CharT>& s, const Predicate& pred){
      TrimEnd(s, pred);
      TrimStart(s, pred);
    }

    template <typename CharT>
    void Trim(std::basic_string<CharT>& s) {
      internal::Trim(s);
    }

#ifdef AC_RVALUE_REF
    template <typename CharT>
    std::basic_string<CharT> Lower(std::basic_string<CharT>&& s){
      ToLower(s);
      return s;
    }

    template <typename CharT>
    std::basic_string<CharT> Upper(std::basic_string<CharT>&& s){
      ToUpper(s);
      return s;
    }
#endif // AC_RVALUE_REF
  }
}